import { Inject, Injectable, Logger } from '@nestjs/common';
import { HashUtil } from '../../../common/utils/hash.util';
import { AuthService } from '../auth/auth.service';
import { Admin } from './entities/admin.entity';
import { Request } from 'express';
import { AccountType } from '../auth/entities/login-log.entity';
import { AccountErrorKey } from '../../../common/constants/user.constant';
import { LoginDto, SaveAdminDto } from './dto/admin.dto';
import { RoleService } from '../role/role.service';
import { FindManyOptions, In } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { IpUtil } from '../../../common/utils/ip.util';
import { I18nContext, I18nService } from 'nestjs-i18n';
import { ResponseUtil } from '../../../common/utils/response.util';

@Injectable()
export class AdminService {
  private readonly logger = new Logger(AdminService.name);
  constructor(
    private readonly authService: AuthService,
    private readonly roleService: RoleService,
    private readonly configService: ConfigService,
    @Inject(I18nService)
    private readonly i18n: I18nService,
  ) {}

  async login(loginDto: LoginDto, request: Request) {
    await this.authService.checkLoginIpBlackList(IpUtil.getRealIP(request));
    try {
      await this.authService.checkAndDeleteCaptcha(loginDto.captcha);
      const admin = await Admin.findOne({
        where: { email: loginDto.email },
        relations: {
          roles: {
            menus: true,
            permissions: false,
          },
        },
      });
      if (!admin) throw new Error(AccountErrorKey.ACCOUNT_OR_PASSWORD_ERROR);
      HashUtil.checkPassword(loginDto.password, admin?.password);
      return {
        admin,
        token: await this.authService.getTokenAndCreateLoginLog(
          admin.id,
          admin.roles,
          request,
          AccountType.ADMIN,
        ),
      };
    } catch (error) {
      this.logger.error('admin login error:', error);
      const count = await this.authService.setLoginIpBlackList(
        IpUtil.getRealIP(request),
      );
      const message = this.i18n.translate(
        `${ResponseUtil.index}.${error?.message || ''}`,
        {
          lang: I18nContext.current().lang,
          args: {
            ['count']: count,
          },
        },
      );
      throw new Error(message);
    }
  }

  async save(saveDto: SaveAdminDto) {
    const admin = await Admin.findOneBy({ email: saveDto.email });
    if (admin && admin.id !== saveDto?.id) {
      throw new Error(AccountErrorKey.EXIST);
    }

    if (saveDto?.roleIds?.length) {
      saveDto.roles = await this.roleService.find({
        where: { id: In(saveDto.roleIds) },
      });
    }

    if (saveDto?.password || !saveDto?.id) {
      const defaultPassword = this.configService.get<string>('ADMIN_PASSWORD');
      saveDto.password = HashUtil.encryption(
        saveDto?.password ?? defaultPassword,
      );
    }
    return await Admin.save(Admin.create(saveDto));
  }

  async findAndCount(options: FindManyOptions<Admin>) {
    const [rows, total] = await Admin.findAndCount(options);
    return {
      rows,
      total,
    };
  }
}
